package Rules;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;

import java.util.HashMap;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

import data.ClockInterface;
import data.ProfileList;

import storage.FieldInfo;
import storage.Profile;
import storage.Rule;

import fileIO.CellIO;


public class RuleChecker {

	/**
	 * @param args
	 * @throws ParseException 
	 */

	@SuppressWarnings("static-access")
	public static ArrayList<Integer> ruleHighlight(Row row) throws ParseException {
		String subjectCell = "", targetCell = "";
		ArrayList<Integer> HLCell = new ArrayList<Integer>();
		int cneeCol = FieldInfo.getCneeColumn();		
		String cnee = CellIO.ConverttoStr(row.getCell(cneeCol));
		Profile cneeProfile = ProfileList.profileList.get(cnee);
		String vendor = "";
		if(FieldInfo.containKey("Vendor")){
			vendor = CellIO.ConverttoStr(row.getCell(FieldInfo.getFieldColumn("Vendor")));		
			if(ProfileList.profileList.containsKey(cnee+"-"+vendor)){
				cneeProfile = ProfileList.profileList.get(cnee + "-" + vendor);
			}
		}
		Object[] KeySet = cneeProfile.ruleList.keySet().toArray();
		for(int keyCount=0;keyCount<KeySet.length;keyCount++){
			ArrayList<Rule> ruleList = cneeProfile.ruleList.get(KeySet[keyCount]);
			HashMap<Integer, ArrayList<Integer>> ruleGroup = new HashMap<Integer,ArrayList<Integer>>();
			boolean[] bool = new boolean[ruleList.size()];
			String[] operator = new String[ruleList.size()];
			String curField = ruleList.get(0).field;
			System.out.println(curField);
			Cell curFieldCell = row.getCell(FieldInfo.getFieldColumn(curField));
			String curFieldStr="";
			if(curFieldCell.getCellType()!=Cell.CELL_TYPE_BLANK){
				continue;
			}
			for(int ruleCount=0;ruleCount<ruleList.size();ruleCount++){
				Rule curRule = ruleList.get(ruleCount);				
				if(curRule.active && curFieldStr.equals("")){
					boolean result = false;
					String subjectField = curRule.subjectField;
					String value = curRule.value;
					String equality = curRule.equality;
					String targetField = curRule.targetField;					
					String connector = curRule.connector;
					int groupNo = curRule.groupNo;
					
					if(subjectField!=null){
						String subjectFieldType = FieldInfo.getFieldType(subjectField);		
						if(subjectField.toString().equals("TODAY"))
							subjectCell = ClockInterface.getTodayDate("MM/dd/yy");
						else if (subjectFieldType.equals("DATE"))
							subjectCell = ClockInterface.DateToStr(row.getCell(FieldInfo.getFieldColumn(subjectField)).getDateCellValue());
						else
							subjectCell = CellIO.ConverttoStr(row.getCell(FieldInfo.getFieldColumn(subjectField)));
						
						if (subjectFieldType.equals("DATE")){
							if(equality!=null&&targetField!=null){
								boolean chkDeep = false;
								if(targetField.toString().equals("TODAY")){
									chkDeep = true;
									targetCell = ClockInterface.getTodayDate("MM/dd/yy");
								}else if(row.getCell(FieldInfo.getFieldColumn(targetField)).toString().equals("")){
									chkDeep = false;
								}else{
									chkDeep = true;
									targetCell = ClockInterface.DateToStr(row.getCell(FieldInfo.getFieldColumn(targetField)).getDateCellValue());
								}
								if (chkDeep){
									Calendar subjectDate = Calendar.getInstance();
									Calendar targetDate = Calendar.getInstance();
									if(subjectField!="TODAY") subjectDate = ClockInterface.StrToCalendar(subjectCell);
									if(targetField!="TODAY") targetDate = ClockInterface.StrToCalendar(targetCell);
									if(equality!=null&&equality.equals("BEFORE")){
										result = aBeforeB(subjectDate,targetDate,Integer.parseInt(value));
									}else if(equality!=null&&equality.equals("AFTER")){
										result = aAfterB(subjectDate,targetDate,Integer.parseInt(value));
									}			
								}
							}
						}else{
							String subject = CellIO.ConverttoStr(row.getCell(FieldInfo.getFieldColumn(subjectField)));
							if (value.equals("NULL")){
								if(subject.equals("")){
									result = true;
								}
							} else if(value.equals(subject)){
								result = true;
							}
						}
					}
					bool[ruleCount]=result;
					operator[ruleCount]=connector;
					if(ruleGroup.containsKey(groupNo)){
						ArrayList<Integer> tempArr = ruleGroup.get(groupNo);
						tempArr.add(ruleCount);
						ruleGroup.put(groupNo,tempArr);
					}else{
						ArrayList<Integer> tempArr = new ArrayList<Integer>();
						tempArr.add(ruleCount);
						ruleGroup.put(groupNo,tempArr);
					}
				}
			}
			Object[] ruleKey = ruleGroup.keySet().toArray();
			boolean[] boolByGrp = new boolean[ruleKey.length];
			String[] operatorByGrp = new String[ruleKey.length];
			for (int grpCount=0;grpCount<ruleKey.length;grpCount++){
				ArrayList<Integer> resultPos = ruleGroup.get(ruleKey[grpCount]);
				boolean boolB = false;
				String operatorB = "";
				for (int resultCount=0;resultCount<resultPos.size();resultCount++){
					boolean boolA = bool[resultPos.get(resultCount)];
					String operatorA = operator[resultPos.get(resultCount)];
					if (resultCount==0){
						boolB = boolA;
						operatorB = operatorA;
					}else{
						boolB = booleanChecker(boolA,boolB,operatorB);
						operatorB = operatorA;
					}
				}
				boolByGrp[grpCount]=boolB;
				operatorByGrp[grpCount]=operatorB;
			}
			boolean finalBoolB = false;
			String finalOperatorB = "";
			for (int finalResultCount=0;finalResultCount<boolByGrp.length;finalResultCount++){
				boolean boolA = boolByGrp[finalResultCount];
				String operatorA = operatorByGrp[finalResultCount];
				if (finalResultCount==0){
					finalBoolB = boolA;
					finalOperatorB = operatorA;
				}else{
					finalBoolB = booleanChecker(boolA,finalBoolB,finalOperatorB);
					finalOperatorB = operatorA;
				}
			}
			if(finalBoolB){
				HLCell.add(FieldInfo.getFieldColumn(curField));
			}	
		}
		//check rule
		return HLCell;
	}
	/**
	 * True or False Identifier
	 */
	private static boolean booleanChecker(boolean a, boolean b, String operator){
		boolean booleanChker = false;
		if(operator.equals("AND")){
			booleanChker = intToBool(boolToInt(a)*boolToInt(b));
		}else if(operator.equals("AND NOT")){
			booleanChker = intToBool(boolToInt(!a)*boolToInt(b));
		}else if(operator.equals("OR")){
			booleanChker = intToBool(boolToInt(a)+boolToInt(b));
		}else if(operator.equals("OR NOT")){
			booleanChker = intToBool(boolToInt(!a)+boolToInt(b));
		}
		return booleanChker;
	}
		
	public static int boolToInt(boolean bool){
		if(bool)
			return 1;
		else
			return 0;
	}
	public static boolean intToBool(int num){
		return(num!=0);
	}
	/**
	 * Checks if one calendar is after another by a certain number of days
	 * @param b
	 * @param a
	 * @param days
	 * @return
	 */
	private static boolean aAfterB(Calendar a, Calendar b, int days){
		b.add(Calendar.DAY_OF_YEAR, days);
		if(a.after(b)  || a.equals(b)){
			b.add(Calendar.DAY_OF_YEAR, -days);
			return true;
		}else{
			b.add(Calendar.DAY_OF_YEAR, -days);
			return false;
		}
	}
	/**
	 * Checks if one calendar is before another by a certain number of days
	 * @param b
	 * @param a
	 * @param days
	 * @return
	 */
	private static boolean aBeforeB(Calendar a, Calendar b, int days){
		b.add(Calendar.DAY_OF_YEAR, -days);
		if(a.after(b) || a.equals(b)){
			b.add(Calendar.DAY_OF_YEAR, days);
			return true;
		}else{
			b.add(Calendar.DAY_OF_YEAR, days);
			return false;
		}
	}
}
